package com.ideaaedi.springcloud.jd.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ideaaedi.springcloud.jd.commonds.entity.PageInfo;
import com.ideaaedi.springcloud.jd.commonds.entity.user.po.SysDeptPO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.po.SysTenantPO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.req.SysTenantListReqVO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.resp.SysTenantDetailRespVO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.resp.SysTenantListRespVO;
import com.ideaaedi.springcloud.jd.commonspring.mybatisplus.ServiceImplExt;
import com.ideaaedi.springcloud.jd.commonspring.mybatisplus.tenant.TenantDataScope;
import com.ideaaedi.springcloud.jd.commonspring.mybatisplus.tenant.TenantDataScopeBO;
import com.ideaaedi.springcloud.jd.user.mapper.SysTenantMapper;
import com.ideaaedi.springcloud.jd.user.service.SysDeptService;
import com.ideaaedi.springcloud.jd.user.service.SysTenantService;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统-业务租户 服务实现类
 * <p>
 * 从系统设计上来讲，每一个部门都是一个租户；但从业务上来看，只有业务租户，该业务租户下的部门只是它的部门，而不是新的租户
 * 即：租户tenant是实际概念(其值对应各部门的path)， 而业务租户bizTenant是抽象概念（系统设计上将某层级的tenant作为业务租户，该层级及该层级下的tenant都属于该bizTenant）
 * <p>
 * <pre>
 *  tenant > bizTenant的关系：
 *
 *                                     tenant1
 *                               /                \
 *                     tenant2 (bizTenantA)   tenant3 (bizTenantB)
 *                 /           \                /           \
 *          tenant4         tenant5       tenant6         tenant7
 * </pre>
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.5.B
 */
@Service
public class SysTenantServiceImpl extends ServiceImplExt<SysTenantMapper, SysTenantPO> implements SysTenantService {

    @Resource
    private SysDeptService sysDeptService;
    
    @NonNull
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<SysTenantPO> createIfMiss(@NonNull Collection<Integer> deptIds) {
        if (CollectionUtils.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        // 过滤
        Set<Integer> deptIdSet = new HashSet<>(deptIds);
        List<SysTenantPO> list = list(new LambdaQueryWrapper<SysTenantPO>()
                .select(SysTenantPO::getId, SysTenantPO::getDeptId)
                .in(SysTenantPO::getDeptId, deptIdSet)
        );
        Set<Integer> existDeptIdSet = list.stream().map(SysTenantPO::getDeptId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        deptIdSet.removeAll(existDeptIdSet);
        if (CollectionUtils.isEmpty(deptIdSet)) {
            return Collections.emptyList();
        }
        // 保存
        List<SysTenantPO> poList = deptIdSet.stream().map(x -> {
            SysTenantPO sysTenant = new SysTenantPO();
            sysTenant.setId(IdWorker.getId());
            sysTenant.setDeptId(x);
            return sysTenant;
        }).collect(Collectors.toList());
        saveBatch(poList);
        return poList;
    }
    
    @NonNull
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<SysTenantPO> removeIfExist(@NonNull Collection<Integer> deptIds) {
        if (CollectionUtils.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        List<SysTenantPO> list = list(new LambdaQueryWrapper<SysTenantPO>()
                .in(SysTenantPO::getDeptId, deptIds)
        );
        removeBatchByIds(list);
        return list;
    }
    
    @Nullable
    @Override
    public SysTenantDetailRespVO detail(Long id) {
        Objects.requireNonNull(id, "id cannot be null.");
        SysTenantPO po = getById(id);
        if (po == null) {
            return null;
        }
        Integer deptId = po.getDeptId();
        SysDeptPO dept = sysDeptService.getById(deptId);
        if (dept == null) {
            return null;
        }
        SysTenantDetailRespVO resp = new SysTenantDetailRespVO();
        resp.setId(po.getId());
        resp.setDeptId(dept.getId());
        resp.setDeptCode(dept.getCode());
        resp.setDeptName(dept.getName());
        resp.setTenant(dept.getTenant());
        resp.setRemark(po.getRemark());
        return resp;
    }
    
    @Override
    public PageInfo<SysTenantListRespVO> list(SysTenantListReqVO req) {
        int pageNum = req.getPageNum();
        int pageSize = req.getPageSize();
        // 分页查
        IPage<SysTenantListRespVO> pageInfo = new Page<>(pageNum, pageSize);
        IPage<SysTenantListRespVO> page = this.baseMapper.list(pageInfo, req);
        return PageInfo.of(page.getTotal(), pageNum, pageSize, page.getRecords());
    }
    
    @Override
    public boolean belongBizTenant(@NonNull String tenant) {
        Objects.requireNonNull(tenant, "tenant cannot be null.");
        return this.baseMapper.selectBizTenantDeptId(tenant) != null;
    }
    
    @NonNull
    @Override
    @TenantDataScope(value = TenantDataScopeBO.IGNORE_URD)
    public Map<String, String> mappingTenantName(@Nullable Collection<String> tenantColle, boolean onlyBizTenant) {
        if (CollectionUtils.isEmpty(tenantColle)) {
            return Collections.emptyMap();
        }
        Set<Integer> deptIdSet;
        
        // 查询租户对应的部门id
        if (onlyBizTenant) {
            deptIdSet = list(new LambdaQueryWrapper<SysTenantPO>()
                    .select(SysTenantPO::getDeptId)
            )
                    .stream()
                    .filter(x -> x != null && x.getDeptId() != null)
                    .map(SysTenantPO::getDeptId)
                    .collect(Collectors.toSet());
            if (CollectionUtils.isEmpty(deptIdSet)) {
                return Collections.emptyMap();
            }
            Set<String> allBizTenantPathSet = sysDeptService.list(new LambdaQueryWrapper<SysDeptPO>()
                            .select(SysDeptPO::getPath)
                            .in(SysDeptPO::getId, deptIdSet))
                    .stream().filter(Objects::nonNull)
                    .map(SysDeptPO::getPath).collect(Collectors.toSet());
    
            // 过滤，使只剩下属于业务租户的tenant
            tenantColle = tenantColle.stream().filter(x -> {
                for (String bizTenantPath : allBizTenantPathSet) {
                    if (x.startsWith(bizTenantPath)) {
                        return true;
                    }
                }
                return false;
            }).collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(tenantColle)) {
            return Collections.emptyMap();
        }
        
        // 根据部门id 查询到 path与name map
        LambdaQueryWrapper<SysDeptPO> queryWrapper = new LambdaQueryWrapper<SysDeptPO>()
                .select(SysDeptPO::getPath, SysDeptPO::getName)
                .in(SysDeptPO::getPath, tenantColle);
        return sysDeptService.list(queryWrapper)
                .stream()
                .filter(x -> x != null && x.getPath() != null && x.getName() != null)
                .collect(Collectors.toMap(SysDeptPO::getPath, SysDeptPO::getName));
    }
}
